#include <ai/GodOfAI.h>
//#include <ctime>
#include <windows.h>

GodOfAI* GodOfAI::s_Instance = NULL;

GodOfAI* GodOfAI::GetInstance()
{
	if (GodOfAI::s_Instance == NULL)
	{
		GodOfAI::s_Instance = new GodOfAI(MAP_SIZE);		
	}
	return GodOfAI::s_Instance;
}

GodOfAI::GodOfAI(int _size):size(_size), s_size(_size * _size)
{
	//Khai bao ma tran ke
	/*s_matrix = new int*[s_size];
	for (int i = 0; i < s_size; i++)
	{
		s_matrix[i] = new int[s_size];
	}*/

	data = AI::GetInstance()->GetBoard();
	temp_Data = new int[_size * _size]; 

	//Cap phat bo nho
	mainLine = new int[_size * _size];
	saveAllLine = new int*[9999]; // luu lai khoang 999 duong di
	countSaveAllLine = new int[9999]; // co the ko dung
	saveLine = new int[_size * _size];
	saveADeadLine = new int[_size * _size];
	s_Area = new Area[s_size];
}

int GodOfAI::GetDirection()
{
	UpdateMainLine();

	if (hasMainLine)
	{
		return GetDirection(mainLine[0]);
	}
	return DIRECTION_NONE;
}

int GodOfAI::GetDirection(int vert)
{
	Position pos_vert = GetPositionFormVertice(vert);
	if (pos_vert.x == currentPos.x && pos_vert.y > currentPos.y)
		return DIRECTION_DOWN;
	if (pos_vert.x == currentPos.x && pos_vert.y < currentPos.y)
		return DIRECTION_UP;
	if (pos_vert.y == currentPos.y && pos_vert.x > currentPos.x)
		return DIRECTION_RIGHT;
	if (pos_vert.y == currentPos.y && pos_vert.x < currentPos.x)
		return DIRECTION_LEFT;
	return DIRECTION_NONE;
}


void GodOfAI::ClearArea()
{
	for (int i = 0; i < s_size; i++)
	{
		s_Area[i].area = 0;
		s_Area[i].vert = s_size;
	}
}
bool GodOfAI::WasAllVerticeArea(int &otherVerticeZone)
{
	for (int i = 0; i < s_size; i++)
	{
		if (temp_Data[i] == 0 && !WasVerticeArea(i))
		{
			otherVerticeZone = i;
			return false;
		}
	}
	return true;
}

bool GodOfAI::WasVerticeArea(int vert)
{
	for (int i = 0; i < s_size; i++)
	{
		if (s_Area[i].vert == vert)
		{
			return true;
		}
	}
	return false;
}
void GodOfAI::SetAreaForVerticeWent(int areaIndex)
{
	for (int i = 0; i < s_size; i++)
	{
		if (temp_Data[i] != 0)
		{
			s_Area[lengthOfArea].vert = i;
			s_Area[lengthOfArea].area = areaIndex;
			lengthOfArea++;
		}
	}
}

void GodOfAI::TryFindArea(int vStart, int areaIndex)
{
	for (int i = 1; i <= 4; i++)
	{		
		int vert = GetVerticeAround(vStart, i);
		if (vert > p_NONE && temp_Data[vert] == 0 && !WasVerticeArea(vert))
		{			
			s_Area[lengthOfArea].vert = vert;
			s_Area[lengthOfArea].area = areaIndex;
			lengthOfArea++;
			TryFindArea(vert, areaIndex);
		}
	}
}

void GodOfAI::SetArea()
{
	ClearArea();

	lengthOfArea = 0;
	int areaIndex = 1;
	SetAreaForVerticeWent(areaIndex);
	
	int otherVerticeZone = 0;
	while (!WasAllVerticeArea(otherVerticeZone))
	{
		areaIndex++;
		s_Area[lengthOfArea].vert = otherVerticeZone;
		s_Area[lengthOfArea].area = areaIndex;
		lengthOfArea++;
		TryFindArea(otherVerticeZone, areaIndex);
	}
}


void GodOfAI::TryFindVertice(int startVert, int endVert)
{

}

void GodOfAI::TryFindAEndLine(int vStart, int count)
{
	for(int i = 1; i <= 8; i++)
	{
		int vert = GetVerticeAround(vStart, i);
		if(vert > p_NONE && data[vert] != 0 && !HasMarkVertice(vert, saveADeadLine))
		{		
			saveADeadLine[count] = vert;
			TryFindAEndLine(vert, count + 1);

			if(hasADeadLine)
			{
				return;
			}
		}
	}

	Position pos = GetPositionFormVertice(saveADeadLine[count - 1]);
	if(pos.x == 0 || pos.x == 10 || pos.y == 0 || pos.y == 10)
	{
		hasADeadLine = true;
	}
}

bool GodOfAI::IsEndLineCanDiv(int endLine)
{
	hasADeadLine = false;

	//neu no la dinh cuoi roi thi return luon
	Position pos = GetPositionFormVertice(endLine);
	if(pos.x == 0 || pos.x == 10 || pos.y == 0 || pos.y == 10)
	{
		hasADeadLine = true;
		return hasADeadLine;
	}

	int* arrVertCanEnd = new int[8];
	int c_arrVertCanEnd = 0;

	for(int i = 1; i <= 8; i++)
	{
		int vert = GetVerticeAround(endLine, i);
		if(vert > p_NONE && data[vert] != 0)
		{
			arrVertCanEnd[c_arrVertCanEnd++] = vert;
		}
	}
	
	for (int j = 0; j < c_arrVertCanEnd; j++)
	{
		if(hasADeadLine)
		{
			return hasADeadLine;
		}

		ClearVertices(saveADeadLine);
		TryFindAEndLine(j, 0);
	}
	return hasADeadLine;
}

void GodOfAI::TryFindAllLine(int vStart, int count)
{
	for (int i = 1; i <= 4; i++)
	{
		
		int vert = GetVerticeAround(vStart, i);
		if (vert > p_NONE && data[vert] == 0 && !HasMarkVertice(vert, saveLine))
		{
			saveLine[count] = vert;
			TryFindAllLine(vert, count + 1);

			if (hasMainLine)
			{
				return;
			}
		}
	}
	
	if (count > 0 && IsEndLineCanDiv(saveLine[count - 1]))
	{
		MakeTempData(saveLine, count);

		//if (GetLevelLiveVert(saveLine[count - 1], temp_Data) > 0)
		for (int i = 1; i <= 4; i++)
		{
			int vert = GetVerticeAround(saveLine[count - 1], i);
			if (vert == p_NONE)
			{
				continue;
			}

			hasLiveToEnemy = false;
			TryFindVertice(vert, currentEnemyVert);//kiem tra xem co duong den currentEnemyVert hay ko?

			if (hasLiveToEnemy)// neu co next
			{
				continue;
			}
			else
			{
				//find max enemy line
				//find max my line
				//if max my line > max enemy line => push to mainLine and hasMainLine = true

				if (hasMainLine)
				{
					return;
				}
			}
		}

		/*saveAllLine[countAllLine] = new int[count];//day la bien toan cuc nho delete bo nho 
		countSaveAllLine[countAllLine] = count;// co the thay the bang (sizeof(countSaveAllLine[i])/sizeof(*countSaveAllLine[i])) 
		
		for(int j = 0; j < count; j++)
		{
			saveAllLine[countAllLine][j] = saveLine[j];
		}

		countAllLine++;*/
	}
}

void GodOfAI::MakeTempData(int* arrData, int lenght)
{
	//gan lai mang data cho temp_data
	for (int i = 0; i < s_size; i++)
	{
		temp_Data[i] = data[i];
	}

	//Set gia tri gia lap
	for (int i = 0; i < lenght; i++)
	{
		temp_Data[arrData[i]] = 5;// dinh ko di duoc
	}
}

void GodOfAI::MakeTheBestLine()
{
	if(GetLevelLiveVert(currentVert) > 0)
	{
		ClearVertices(saveLine);

		countAllLine = 0;
		int t, d, k;
		t = GetTickCount();
		TryFindAllLine(currentVert, 0);

		//sau khi tim ma ko co win line 
		if (!hasMainLine)
		{
			//to do something to have a winLine
		}

		/*
		cout << endl;
		for (int i = 0; i < countAllLine; i++)
		{
			for (int j = 0; j < countSaveAllLine[i]; j++)
			{
				cout << saveAllLine[i][j] << " ";
			}
			cout << endl;
		}
		cout << endl;


		enemyFreeVert = 0;
		myFreeVert = 0;
		indexTheBestLine = 0;

		//Tim duong di toi uu
		for (int i = 0; i < countAllLine; i++)
		{			
			MakeTempData(saveAllLine[i], countSaveAllLine[i]);

			if (GetLevelLiveVert(saveAllLine[i][countSaveAllLine[i] - 1], temp_Data) == 0)
			{
				continue;
			}

			SetArea();

			cout << endl;
			for (int j = 0; j < lengthOfArea; j++)
			{
				cout << s_Area[j].vert << "-" << s_Area[j].area <<endl;
			}

			if (myFreeVert >= enemyFreeVert)
			{
				indexTheBestLine = countAllLine;
			}
		}

		if (myFreeVert < enemyFreeVert)
		{
			//Se tinh sau
			hasMainLine = false;
		}
		else
		{
			hasMainLine = true;
		}

		//Gan duong di ma mainLine de delete	
		for (int i = 0; i < countSaveAllLine[indexTheBestLine]; i++)
		{
			mainLine[i] = saveAllLine[indexTheBestLine][i];
		}
		
		//Delete bo nho khi ket thuc 1 luot tinh toan
		for (int i = 0; i < countAllLine; i++)
		{
			delete saveAllLine[i];
		}

		*/
		d = GetTickCount();
		k = d - t;
		k = k;
		/*
		t = GetTickCount();
		cout << endl;
		for(int i = 0; i < countAllLine; i++)
		{
			for(int j = 0; j < countSaveAllLine[i]; j++)
			{
				cout << saveAllLine[i][j] << " ";
			}
			cout << endl;
		}
		cout << endl;
		d = GetTickCount();
		k = d - t;
		cout << endl;*/

	}
	else
	{
		//het duong di hasMainLine = false
	}
}

void GodOfAI::UpdateMainLine()
{
	//Cap nhat lai vi tri dang dung
	currentVert = GetVerticeFromPosition(AI::GetInstance()->GetMyPosition());
	currentEnemyVert = GetVerticeFromPosition(AI::GetInstance()->GetEnemyPosition());
	currentPos = GetPositionFormVertice(currentVert);

	ClearVertices(mainLine);
	//CreateMatrix();// cap nhat lai ma tran ke
	
	hasMainLine = false;
	MakeTheBestLine();
	//SetArea();

	/*cout << endl;
	for (int i = 0; i < s_size; i++)
	{
	cout << s_Area[i].vert << "-" << s_Area[i].area << " ";
	if (i % 11 == 0)
	cout << endl;
	}
	cout << endl;*/

	//FindMaxLine();//tim duong di dai nhat
}

bool GodOfAI::HasMarkVertice(int vert, int* arrVert)
{
	for (int i = 0; i < s_size; i++)
	{
		if (arrVert[i] == vert)
		{
			return true;
		}
	}
	return false;
}

void  GodOfAI::ClearVertices(int* arrVert)
{
	for (int i = 0; i < s_size; i++)
	{
		arrVert[i] = s_size;
		//saveLiveLine[i] = s_size;
		//saveLine[i] = s_size;		
		//s_Area[i].vert = s_size;
		//s_Area[i].area = 0;//o da di
	}
}

int GodOfAI::GetVerticeFromPosition(Position pos)
{
	return pos.y * size + pos.x;
}

Position GodOfAI::GetPositionFormVertice(int vert)
{
	Position pos(vert % size, vert / size);
	return pos;
}

int GodOfAI::GetLevelLiveVert(int vert)
{
	int level = 0;
	for(int i = 1; i <= 4; i++)
	{
		if(data[GetVerticeAround(vert, i)] > p_NONE && data[GetVerticeAround(vert, i)] == 0)
		{
			level++;
		}
	}
	return level;
}

int GodOfAI::GetLevelLiveVert(int vert, int* arrData)
{
	int level = 0;
	for (int i = 1; i <= 4; i++)
	{
		if (arrData[GetVerticeAround(vert, i)] > p_NONE && arrData[GetVerticeAround(vert, i)] == 0)
		{
			level++;
		}
	}
	return level;
}

int GodOfAI::GetLevelDeadVert(int vert)
{
	int level = 0;
	for(int i = 1; i <= 8; i++)
	{
		if(data[GetVerticeAround(vert, i)] > p_NONE && data[GetVerticeAround(vert, i)] != 0)
		{
			level++;
		}
	}
	return level;
}

int GodOfAI::GetVerticeAround(int vert, int pos)
{
	if(vert > 0 && vert < s_size)
	{
		switch (pos)
		{
		case p_TOP:
			if (vert - size >= 0)
				return vert - size;
			break;
		case p_DOWN:
			if (vert + size < s_size)
				return vert + size;
			break;
		case p_LEFT:
			if (vert - 1 >= 0 && (GetPositionFormVertice(vert).y == GetPositionFormVertice(vert - 1).y))
				return vert - 1;
			break;
		case p_RIGHT:
			if (vert + 1 < s_size && (GetPositionFormVertice(vert).y == GetPositionFormVertice(vert + 1).y))
				return vert + 1;
			break;
		case p_TOP_LEFT:
			if (vert - size - 1 > 0)
				return vert - size - 1;
			break;
		case p_TOP_RIGHT:
			if (vert - size + 1 > 0)
				return vert - size + 1;
			break;
		case p_DOWN_LEFT:
			if (vert + size - 1 < s_size)
				return vert + size - 1;
			break;
		case p_DOWN_RIGHT:
			if (vert + size + 1 < s_size)
				return vert + size + 1;
			break;
		default:
			return p_NONE;
		}
		return p_NONE;
	}
	return p_NONE;
}

/*
void GodOfAI::CreateMatrix()
{
	for (int i = 0; i < s_size; i++)
	{
		if (data[i] != 0 && i != currentVert)
		{
			for (int j = 0; j < s_size; j++)
			{
				s_matrix[i][j] = 0;
			}
		}
		else
		{
			for (int j = 0; j < s_size; j++)
			{
				if (i == j)
				{
					s_matrix[i][j] = 0;
				}
				else
				{
					Position pos_i = GetPositionFormVertice(i);
					Position pos_j = GetPositionFormVertice(j);

					if (data[j] == 0)
					{
						if ((pos_i.x == pos_j.x && ((pos_i.y == pos_j.y - 1) || (pos_i.y == pos_j.y + 1))) ||
								(pos_i.y == pos_j.y && ((pos_i.x == pos_j.x - 1) || (pos_i.x == pos_j.x + 1))))
						{
							s_matrix[i][j] = 1;
						}
						else
						{
							s_matrix[i][j] = 0;
						}
					}
					else
					{
						s_matrix[i][j] = 0;
					}
				}
			}
		}
	}
}
*/




void GodOfAI::FindMaxLine()
{
	countMainLine = 0;

	saveLine[0] = currentVert;
	TryFindMaxLine(currentVert, 1);
}

void GodOfAI::TryFindMaxLine(int vStart, int count)
{
	for (int i = 1; i <= 4; i++)
	{
		int vert = GetVerticeAround(vStart, i);
		if (vert > p_NONE && data[vert] == 0 && !HasMarkVertice(i, saveLine))
		{
			saveLine[count] = vert;
			TryFindMaxLine(vert, count + 1);
		}
	}
	if (count > 1 && count > countMainLine)
	{
		hasMainLine = true;
		for (int j = 0; j < count; j++)
		{
			mainLine[j] = saveLine[j];
		}
		countMainLine = count;
	}
}